# PlatformTransactionManagerConnectionProvider.java

    package org.codefilarete.stalactite.spring.transaction;

    import java.sql.Connection;

    import org.codefilarete.stalactite.engine.SeparateTransactionExecutor;
    import org.codefilarete.stalactite.sql.ConnectionProvider;
    import org.springframework.jdbc.datasource.DataSourceUtils;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.TransactionDefinition;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.TransactionCallbackWithoutResult;
    import org.springframework.transaction.support.TransactionSynchronizationManager;
    import org.springframework.transaction.support.TransactionTemplate;

    /**
     * {@link ConnectionProvider} acting as a bridge for Spring's {@link PlatformTransactionManager}.
     * One subclass for each known {@link PlatformTransactionManager} exists, prefer them to avoid {@link NoClassDefFoundError} :
     * {@link PlatformTransactionManagerConnectionProvider} could have handled those cases through some constructor or factory method, but it rises an
     * error if the project doesn't have the dependencies due to JPA / Hibernate presence in imports.
     * This class is left public to let one handle an unexpected case.
     *
     * @author Guillaume Mary
     */
    public class PlatformTransactionManagerConnectionProvider implements SeparateTransactionExecutor {

    	/** {@link PlatformTransactionManager} given at construction time. Used for new transaction building. */
    	private final PlatformTransactionManager transactionManager;

    	/** {@link javax.sql.DataSource} extractor from the transaction manager */
    	private final TransactionManagerDataSourceProvider dataSourceProvider;

    	public PlatformTransactionManagerConnectionProvider(PlatformTransactionManager transactionManager, TransactionManagerDataSourceProvider dataSourceProvider) {
    		this.transactionManager = transactionManager;
    		this.dataSourceProvider = dataSourceProvider;
    	}

    	@Override
    	public Connection giveConnection() {
    		// DataSourceUtils.getConnection(..) gets a connection even if no surrounding transaction exists so we have to check it before
    		if (!TransactionSynchronizationManager.isActualTransactionActive()) {
    			throw new IllegalStateException("No active transaction");
    		} else {
    			return DataSourceUtils.getConnection(dataSourceProvider.getDataSource());
    		}
    	}

    	@Override
    	public void executeInNewTransaction(JdbcOperation jdbcOperation) {
    		TransactionTemplate transactionTemplate = new TransactionTemplate(this.transactionManager);
    		transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    			@Override
    			protected void doInTransactionWithoutResult(TransactionStatus status) {
    				jdbcOperation.execute(giveConnection());
    			}
    		});
    	}
    }